//////////////////////// 接口初探 ////////////////////////

//////////// 类

// class Greeter {

//     greeting: string;

//     constructor(message: string) {
//         this.greeting = message
//     }

//     greet() {
//         return "Hello, " + this.greeting;
//     }

// }

// let greeter = new Greeter("world");

//////////// 继承

// class Animal{
//     move(distanceInMeters:number=0){
//         console.log(`Animal moved ${distanceInMeters}`)
//     }
// }

// class Dog extends Animal{
//     bark(){
//         console.log('Woof! Woof!')
//     }
// }

// const dog = new Dog();
// dog.bark();
// dog.move(10);
// dog.bark();

//////////// 下面我们来看个更加复杂的例子

// class Animal{
//     name:string;
//     constructor(theName:string){
//         this.name = theName;
//     }
//     move(disttanceInMeters: number = 0){
//         console.log(`${this.name} moved ${disttanceInMeters}m.`)
//     }
// }

// class Snake extends Animal {
//     // 派生类包含了一个构造函数，它 必须调用 super()
//     constructor(name:string){
//         super(name);
//     }
//     // 子类重写了父类
//     move(distanceInMeters=5){
//         console.log("Slithering...")
//         // 字类中调用父类的方法
//         super.move(distanceInMeters)
//     }
// }

// class Horse extends Animal{
//     constructor(name: string){
//         super(name)
//     }
//     move(distanceInMeters=45){
//         console.log("Galloping...")
//         super.move(distanceInMeters)
//     }
// }

// let sam = new Snake("Sammy the Python");
// let tom: Animal = new Horse("Tommy the Palomino");

// sam.move();
// tom.move(34);

//////////// 公共，私有与受保护的修饰符

//// 默认为 public，也可以显式声明为public

// class Animal {
//     public name: string;
//     public constructor(theName: string){
//         this.name = theName;
//     }
//     public move(distanceInMeters: number){
//         console.log(`${this.name} moved ${distanceInMeters}m.`)
//     }
// }

//// 当成员被标记成 private时，它就不能在声明它的类的外部访问

// class Animal {
//     private name: string;
//     constructor(theName: string){
//         this.name = theName;
//     }
// }

// // 这里会报错，访问不了私有属性name
// new Animal("Cat").name;


// 然而，当我们比较带有 private或 protected成员的类型的时候，情况就不同了。 
// 如果其中一个类型里包含一个 private成员，
// 那么只有当另外一个类型中也存在这样一个 private成员， 
// 并且它们都是来自同一处声明时，我们才认为这两个类型是兼容的。 
// 对于 protected成员也使用这个规则。
// 下面来看一个例子，更好地说明了这一点：

// class Animal{
//     private name: string;
//     constructor(theName:string){
//         this.name=theName;
//     }
// }

// class Rhino extends Animal{
//     constructor(){
//         super("Rhino")
//     }
// }

// class Employee{
//     private name: string;
//     constructor(theName: string){
//         this.name = theName
//     }
// }

// let animal = new Animal("Goat");
// let rhino = new Rhino();
// let employee = new Employee("Bob")

// animal = rhino;
// animal = employee; // 错误: Animal 与 Employee 不兼容.

//// protected修饰符与 private修饰符的行为很相似，但有一点不同， 
//// protected成员在派生类中仍然可以访问

// class Person{
//     protected name: string;
//     constructor(name: string){
//         this.name = name;
//     }
// }

// class Empolyee extends Person{
//     private department: string;
//     constructor(name: string, department: string){
//         super(name);
//         this.department = department;
//     }
//     public getElevatorPitch(){
//         return `Hello, my name is ${this.name} and I work in ${this.department}`;
//     }
// }

// let howard = new Empolyee("Howard","Sales");
// console.log(howard.getElevatorPitch());
// // 不能在 Person类外使用 name，但是我们仍然可以通过 Employee类的实例方法访问
// console.log(howard.name);


//// 构造函数也可以被标记成 protected。 这意味着这个类不能在包含它的类外被实例化，但是能被继承

// class Person{
//     protected name: string;
//     protected constructor(theName: string){
//         this.name = theName;
//     }
// }

// class Employee extends Person{
//     private department: string;
//     constructor(name:string,department:string){
//         super(name);
//         this.department = department;
//     }
//     public getElevatorPitch(){
//         return `Hello, my name is ${this.name} and I work in ${this.department}`
//     }   
// }

// let howard = new Employee("Howard","Sales");
// let john = new Person("John"); // 错误: 'Person' 的构造函数是被保护的


//////////// readonly修饰符

// 你可以使用 readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化

// class Octopus {
//     readonly name: string;
//     readonly numberOfLegs: number = 8;
//     constructor(theName: string){
//         this.name = theName;
//     }
// }

// let dad = new Octopus("Man with the 8 strong legs");
// dad.name = "Man with the 3-piece suit";// 错误! name 是只读的. 

//////////// 参数属性

class Octopus{
    readonly numberOfLegs: number = 8;
    constructor(readonly name: string){

    }
}

//////////// 存取器

// class Employee{
//     fullName: string = '';       
// }

// let employee = new Employee();
// employee.fullName = "Bob Smith";
// if(employee.fullName){
//     console.log(employee.fullName)
// }

// let passcode = "secret passcode";

// class Employee{

//     private _fullName: string = '';

//     get fullName(): string{
//         return this._fullName;
//     }

//     set fullName(newName: string){
//         if(passcode&&passcode==="secret passcode"){
//             this._fullName = newName;
//         }
//         else {
//             console.log("Error: Unauthorized update of employee!");
//         }
//     }

// }

// let employee = new Employee();
// employee.fullName = "Bol Smith";
// if(employee.fullName){
//     alert(employee.fullName)
// }

//////////// 静态属性

// class Grid{
//     static origin = {x: 0, y: 0};
//     constructor(public scale:number){

//     }
//     calculateDistanceFromOrigin(point:{x:number,y:number}){
//         let xDist = (point.x - Grid.origin.x);
//         let yDist = (point.y - Grid.origin.y);
//         return Math.sqrt(xDist*xDist+yDist*yDist)/this.scale;
//     }
// }

// let grid1 = new Grid(1.0);
// let grid2 = new Grid(5.0);

// console.log(grid1.calculateDistanceFromOrigin({x:10,y:10}))
// console.log(grid2.calculateDistanceFromOrigin({x:10,y:10}))

//////////// 抽象类

// abstract class Animal{
//     abstract makeSound(): void;
//     move(): void{
//         console.log('roaming the earth...');
//     }
// }

// 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 
// 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 
// 然而，抽象方法必须包含 abstract关键字并且可以包含访问修饰符。

// abstract class Department{

//     constructor(public name: string){

//     }

//     printName(): void{
//         console.log('Department name: '+this.name);
//     }

//     abstract printMeeting(): void; // 必须在派生类中实现

// }

// class AccountingDepartment extends Department{
    
//     constructor(){
//         super('Accounting and Auditing');
//     }

//     printMeeting(): void {
//         console.log('The Accounting Department meets each Monday at 10am.')
//     }

//     generateReports(): void {
//         console.log('Generating accounting reports');
//     }

// }

// let department: Department; // 允许创建一个对抽象类型的引用
// //department = new Department(); // 错误：不能创建一个抽象类的实例
// department = new AccountingDepartment(); // 允许对一个抽象字类进行实例化和赋值
// department.printName();
// department.printMeeting();


//////////// 高级技巧

// 构造函数
// class Greeter{
//     greeting: string;
//     constructor(message:string){
//         this.greeting = message;
//     }
//     greet(){
//         return "Hello, "+this.greeting;
//     }
// }

// let greeter: Greeter;
// greeter = new Greeter("world");
// console.log(greeter.greet());

// class Greeter {
//     static standardGreeting = "Hello, there";
//     greeting: string = '';
//     greet() {
//         if (this.greeting) {
//             return "Hello, " + this.greeting;
//         }
//         else {
//             return Greeter.standardGreeting;
//         }
//     }
// }

// let greeter1: Greeter;
// greeter1 = new Greeter();
// console.log(greeter1.greet());

// let greeterMaker: typeof Greeter = Greeter;
// greeterMaker.standardGreeting = "Hey there!";

// let greeter2: Greeter = new greeterMaker();
// console.log(greeter2.greet());

//// 把类当做接口使用

// class Point {
//     x: number = 0;
//     y: number = 0;
// }

// interface Point3d extends Point {
//     z: number;
// }

//let point3d: Point3d = {x: 1, y: 2, z: 3};

